// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package cmplx

import "math"

// 下面的原始C代码、长注释和常量
// 来自http:
// go代码是原始C的简化版本。
// 
// Cephes数学库发行版2.8:2000年6月
// 1984年、1987年、1989年、1992年版权所有，2000年由Stephen L.Moshier 
// 
// 自述文件位于http:
// 此档案中的某些软件可能来自《数学函数的方法和程序》（Prentice Hall或Simon&Schuster 
// 国际，1989）一书或者从Cephes数学库，
// 商业产品。无论哪种情况，它都是作者的版权。
// 您在这里看到的内容可以免费使用，但不提供任何支持或担保。
// 
// 本书中两个已知的印刷错误在这里的
// 伽马函数和不完整的beta 
// 积分的源代码列表中修复。
// 
// Stephen L.Moshier 
// moshier@na-net.ornl.gov 

// 复正弦
// 
// 说明：
// 
// 如果
// z=x+iy，
// 
// 然后
// 
// w=sinx cosh y+i cos x sinh y。
// 
// csin（z）=-i csinh（iz）。
// 
// 准确度：
// 
// 相对误差：
// 算术域试验峰值均方根值
// DEC-10，+108400 5.3e-17 1.3e-17 
// IEEE-10，+10 30000 3.8e-16 1.0e-16 
// 也通过csin（casin（z））=z进行测试。

// Sin返回x的正弦值。
func Sin(x complex128) complex128 {
	switch re, im := real(x), imag(x); {
	case im == 0 && (math.IsInf(re, 0) || math.IsNaN(re)):
		return complex(math.NaN(), im)
	case math.IsInf(im, 0):
		switch {
		case re == 0:
			return x
		case math.IsInf(re, 0) || math.IsNaN(re):
			return complex(math.NaN(), im)
		}
	case re == 0 && math.IsNaN(im):
		return x
	}
	s, c := math.Sincos(real(x))
	sh, ch := sinhcosh(imag(x))
	return complex(s*ch, c*sh)
}

// 复双曲正弦
// 
// 说明：
// 
// /csinh z=（cexp（z）-cexp（-z））/2 
// /=sinh x*cos y+i cosh x*sin y。
// 
// 精度：
// 
// 相对误差：
// 算术域#试验峰值rms 
// IEEE-10，+10 30000 3.1e-16 8.2e-17 

// Sinh返回x的双曲正弦值。
func Sinh(x complex128) complex128 {
	switch re, im := real(x), imag(x); {
	case re == 0 && (math.IsInf(im, 0) || math.IsNaN(im)):
		return complex(re, math.NaN())
	case math.IsInf(re, 0):
		switch {
		case im == 0:
			return complex(re, im)
		case math.IsInf(im, 0) || math.IsNaN(im):
			return complex(re, math.NaN())
		}
	case im == 0 && math.IsNaN(re):
		return complex(math.NaN(), im)
	}
	s, c := math.Sincos(imag(x))
	sh, ch := sinhcosh(real(x))
	return complex(c*sh, s*ch)
}

// 复圆余弦
// 
// 说明：
// 
// 如果
// z=x+iy，
// 
// 那么
// 
// w=cos x cosh y-i sin x sinh y。
// 
// 准确度：
// 
// 相对误差：
// 算术域试验峰值均方根值
// DEC-10，+108400 4.5e-17 1.3e-17 
// IEEE-10，+10 30000 3.8e-16 1.0e-16 

// Cos返回x的余弦。
func Cos(x complex128) complex128 {
	switch re, im := real(x), imag(x); {
	case im == 0 && (math.IsInf(re, 0) || math.IsNaN(re)):
		return complex(math.NaN(), -im*math.Copysign(0, re))
	case math.IsInf(im, 0):
		switch {
		case re == 0:
			return complex(math.Inf(1), -re*math.Copysign(0, im))
		case math.IsInf(re, 0) || math.IsNaN(re):
			return complex(math.Inf(1), math.NaN())
		}
	case re == 0 && math.IsNaN(im):
		return complex(math.NaN(), 0)
	}
	s, c := math.Sincos(real(x))
	sh, ch := sinhcosh(imag(x))
	return complex(c*ch, -s*sh)
}

// 复双曲余弦
// 
// 说明：
// 
// ccosh（z）=余弦x余弦y+i正弦x正弦y。
// 
// 精度：
// 
// 相对误差：
// 算术域#试验峰值均方根
// IEEE-10，+1030000 2.9e-16 8.1e-17 

// Cosh返回x的双曲余弦。
func Cosh(x complex128) complex128 {
	switch re, im := real(x), imag(x); {
	case re == 0 && (math.IsInf(im, 0) || math.IsNaN(im)):
		return complex(math.NaN(), re*math.Copysign(0, im))
	case math.IsInf(re, 0):
		switch {
		case im == 0:
			return complex(math.Inf(1), im*math.Copysign(0, re))
		case math.IsInf(im, 0) || math.IsNaN(im):
			return complex(math.Inf(1), math.NaN())
		}
	case im == 0 && math.IsNaN(re):
		return complex(math.NaN(), im)
	}
	s, c := math.Sincos(imag(x))
	sh, ch := sinhcosh(real(x))
	return complex(c*ch, s*sh)
}

// 计算sinh和cosh 
func sinhcosh(x float64) (sh, ch float64) {
	if math.Abs(x) <= 0.5 {
		return math.Sinh(x), math.Cosh(x)
	}
	e := math.Exp(x)
	ei := 0.5 / e
	e *= 0.5
	return e - ei, e + ei
}
